﻿using LargeScreen.WPF.Base;
using LargeScreen.WPF.Models;
using LiveCharts;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.IO.Ports;
using System.Linq;
using System.Management;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Threading;

namespace LargeScreen.WPF.ViewModels
{
    public class MainViewModel : NotifyBase
    {
		DispatcherTimer timer = new DispatcherTimer();

		private DateTime _currentTime;

		public DateTime CurrentTime
		{
			get { return _currentTime; }
			set { SetProperty(ref _currentTime, value); }
		}

        #region 串口下拉与相关属性

        private string? _portName;

        public string? PortName
        {
            get { return _portName; }
            set { SetProperty(ref _portName, value); }
        }

        public int BaudRate { get; set; } = 9600;
        public int DataBits { get; set; } = 8;
        public string Parity { get; set; } = "None";
        public string StopBits { get; set; } = "1";
        public List<string> PortList { get; set; }
        public List<int> BaudRateList { get; set; } = new List<int>
        {
            4800, 9600, 14400, 19200, 38400, 115200
        };
        public List<int> DataBitsList { get; set; } = new List<int>
        {
            5, 7, 8
        };
        public List<string> ParityList { get; set; }
        public List<string> StopBitsList { get; set; }

        #endregion

        #region 运行环境状态

        private double _CPU;

        public double CPU
        {
            get { return _CPU; }
            set { SetProperty(ref _CPU, value); }
        }

        private double _memory;

        public double Memory
        {
            get { return _memory; }
            set { SetProperty(ref _memory, value); }
        }
        private PerformanceCounter CpuCounter;
        private ManagementClass MemoryCounter;
        #endregion

        private bool _startState;

        public bool StartState
        {
            get { return _startState; }
            set 
            { 
                _startState = value;

                try
                {
                    DoStart();
                }
                catch (Exception ex)
                {
                    ShowMessage(ex.Message, "通信异常", "Orange");
                }
            }
        }

        #region 图表数据

        public ChartValues<float> TemperatureValues { get; set; } = new ChartValues<float>()
        {
            38,70,57,45,60,38,70,57,45,38,70,57,45,38,70,57,45,38,70,57,45
        };

        public ChartValues<float> HumidityValues { get; set; } = new ChartValues<float>()
        {
            38,70,57,45,60,57,45,38,70,57,45,38,70,57,45,38,70,57,45,38,70
        };

        public ChartValues<float> BrightnessValues { get; set; } = new ChartValues<float>()
        {
            38,70,57,45,60,38,38,70,57,70,57,45,38,70,45,38,70,57,45,57,45
        };

        public ObservableCollection<string> XLabels { get; set; } = new ObservableCollection<string>();

        #endregion

        #region OLED数据

        public string SendText { get; set; } = "OLED显示屏";
        private string _oledText;

        public string OledText
        {
            get { return _oledText; }
            set { _oledText = value; }
        }

        public Command SendTextCommand { get; set; }
        public Command ResendTextCommand { get; set; }

        public ObservableCollection<SendLogModel> LogList { get; set; } = new ObservableCollection<SendLogModel>();

        #endregion

        public DeviceModel DeviceInfo { get; set; } = new DeviceModel();
        public MessageModel MessageInfo { get; set; } = new MessageModel();

        #region 状态灯
        public List<LightModel> LightList { get; set; } = new List<LightModel>();

        public Command LightCommand { get; set; }
        #endregion

        SerialPort serialPort = new SerialPort();

        public MainViewModel()
        {
            SendTextCommand = new Command(OnSendText);
            ResendTextCommand = new Command(OnResendText);
            LightCommand = new Command(OnLight);

            StopBitsList = Enum.GetNames(typeof(StopBits)).ToList();
            StopBits = "One";

            ParityList = Enum.GetNames(typeof(Parity)).ToList();
            Parity = ParityList[0];

            timer.Interval = new TimeSpan(0, 0, 1);
            timer.Tick += (sender, e) =>
            {
                CurrentTime = DateTime.Now;

                if (PortList == null)
                {
                    PortList = SerialPort.GetPortNames().ToList();
                    PortName = PortList.Any() ? PortList[0] : "";
                    this.RaisePropertyChanged(nameof(PortList));
                }
                else if (!PortList.SequenceEqual(SerialPort.GetPortNames()))
                {
                    PortList = SerialPort.GetPortNames().ToList();
                    this.RaisePropertyChanged(nameof(PortList));
                    if (!PortList.Exists(x => x == PortName))
                    {
                        PortName = PortList.Any() ? PortList[0] : "";
                    }
                }
            };
            timer.Start();

            var time = DateTime.Now;
            for (int i = 20; i > 0; i--)
            {
                XLabels.Add(time.AddSeconds(i * -1).ToString("ss"));
            }

            for (ushort i = 0; i < 6; i++)
            {
                LightList.Add(new LightModel
                {
                    Address = i
                });
            }

            for (int i = 0; i < 10; i++)
            {
                LogList.Add(new SendLogModel { LogInfo = $"Hello [{i.ToString("000")}]" });
            }

            CpuCounter = new PerformanceCounter();
            CpuCounter.CategoryName = "Processor";
            CpuCounter.CounterName = "% Processor Time";
            CpuCounter.InstanceName = "_Total";
            MemoryCounter = new ManagementClass();
            Task.Run(async () =>
            {
                while (true)
                {
                    try
                    {
                        CPU = Math.Round(CpuCounter.NextValue(), 2);
                        Memory = GetMemoryUsage();
                    }
                    catch (Exception ex)
                    {
                        Debug.WriteLine($"获取系统资源异常: {ex.Message}");
                    }
                    await Task.Delay(1000); // 每秒更新一次
                }
            });
        }

        private void OnLight(object obj)
        {
            if (!serialPort.IsOpen)
            {
                return;
            }
            try
            {
                if (obj.ToString() == "all")
                {
                    byte state = LightList[5].State ? (byte)31 : (byte)0; // 统一控制
                    byte[] bytes = [0x01, 0x0F, 0x00, 0x00, 0x00, 0x05, 0x01, state, 0x00, 0x00];
                    bytes = CRC16(bytes);

                    SendAndReceive(bytes);

                    foreach (var item in LightList)
                    {
                        item.State = LightList[5].State;
                    }
                }
                else
                {
                    
                }

                SendOledText(OledText);
            }
            catch (Exception ex)
            {
                ShowMessage(ex.Message, "发送异常", "Orange");
            }
        }

        private void OnSendText(object obj)
        {
            if (!serialPort.IsOpen)
            {
                return;
            }
            try
            {
                if (string.IsNullOrEmpty(SendText))
                {
                    throw new Exception("请先输入要发送的文本内容");
                }
                else if (SendText.Length > 60)
                {
                    throw new Exception("OLED显示内容不能超过60个字符");
                }
                else if (SendText.ToList().Exists(x => (int)x > 127))
                {
                    throw new Exception("OLED显示内容只能包含ASCII字符（0-127）");
                }

                SendOledText(OledText);
            }
            catch (Exception ex)
            {
                ShowMessage(ex.Message, "发送异常", "Orange");
            }
        }

        private void OnResendText(object obj)
        {
            if (!serialPort.IsOpen)
            {
                return;
            }
            try
            {
                string text = obj.ToString();
                SendOledText(text);
            }
            catch (Exception ex)
            {
                ShowMessage(ex.Message, "发送异常", "Orange");
            }
        }

        private void SendOledText(string text)
        {
            serialPort.Write(text);
            byte[] textBytes = Encoding.UTF8.GetBytes(SendText);
            List<byte> sendBytes = [0x01, 0x10, 0x00, 0x08];
            sendBytes.Add((byte)(Math.Ceiling(textBytes.Length / 2.0) / 256));
            sendBytes.Add((byte)(Math.Ceiling(textBytes.Length / 2.0) % 256));
            byte len = (byte)textBytes.Length;
            len += (byte)(len % 2);
            sendBytes.Add(len);
            sendBytes.AddRange(textBytes);
            if (textBytes.Length % 2 == 1)
            {
                sendBytes.Add(0x00);
            }
            sendBytes.Add(0x00);
            sendBytes.Add(0x00);
            byte[] crc = CRC16(sendBytes.ToArray());
            sendBytes.AddRange(crc);

            SendAndReceive(sendBytes.ToArray());

            OledText = text;

            LogList.Insert(0, new SendLogModel { LogInfo = text });
            if (LogList.Count > 30)
            {
                LogList.RemoveAt(LogList.Count - 1);
            }
        }

        private double GetMemoryUsage()
        {
            double available = 0;
            double capacity = 0;
            MemoryCounter.Path = new ManagementPath("Win32_PhysicalMemory");
            var moc = MemoryCounter.GetInstances();
            foreach (var item in moc)
            {
                capacity += Convert.ToDouble(item["Capacity"]) / 1024 /1024 /1024.0;
            }
            moc.Dispose();

            MemoryCounter.Path = new ManagementPath("Win32_PerfFormattedData_PerfOS_Memory");
            moc = MemoryCounter.GetInstances();
            foreach (var item in moc)
            {
                available += Convert.ToDouble(item["AvailableMBytes"]) / 1024.0;
            }
            moc.Dispose();
            return (capacity - available) / capacity * 100;
        }

        public void ShowMessage(string message, string title = "运行提示", string color = "#00CFF8")
        {
            MessageInfo.Message = message;
            MessageInfo.Title = title;
            MessageInfo.MsgColor = color;
            MessageInfo.MsgTime = DateTime.Now;
        }

        public void DoStart()
        {
            if (serialPort.IsOpen)
            {
                serialPort.Close();
                ShowMessage("连接已断开！等待连接设备......");
            }
            else
            {
                if (string.IsNullOrEmpty(PortName)) { throw new Exception("请先选择串口"); }

                serialPort.PortName = PortName;
                serialPort.BaudRate = BaudRate;
                serialPort.DataBits = DataBits;
                serialPort.Parity = Enum.Parse<Parity>(Parity);
                serialPort.StopBits = Enum.Parse<StopBits>(StopBits);

                serialPort.Open();

                ShowMessage("连接正常！正在监听接收学习卡数据");

                Task.Run(async () =>
                {
                    while (serialPort.IsOpen)
                    {
                        OnMonitor();
                        
                        await Task.Delay(1000);
                    }
                });
            }
        }

        private int[] lastRandom = [0, 0, 0]; // 温度、湿度、亮度
        private bool[] order = [true, true, true]; // 温度、湿度、亮度
        private Random random = new Random();
        private void OnMonitor()
        {
            // 温湿亮
            byte[] bytes = [0x01, 0x03, 0x00, 0x00, 0x00, 0x03];

            // 计算CRC16并合并到bytes
            byte[] crc = CRC16(bytes);
            byte[] sendBytes = bytes.Concat(crc).ToArray();

            byte[] resp = SendAndReceive(bytes);
            

            if (DeviceInfo.UseTemperatureSim)
            {
                GennerateRandomData(ref lastRandom[0], ref order[0], DeviceInfo.MinTemperatureSim, DeviceInfo.MaxTemperatureSim);
                DeviceInfo.Temperature = lastRandom[0];
            }
            else
            {
                //if (resp.Length < 5 || resp[0] != 0x01 || resp[1] != 0x03)
                //{
                //    ShowMessage("设备响应异常，请检查连接或设备状态！", "通信异常", "Orange");
                //    return;
                //}
                if (resp.Length > 0 && resp[0] == 0x01 && resp[1] == 0x03)
                {
                    DeviceInfo.Temperature = BitConverter.ToInt16([resp[4], resp[3]]) / 10.0f; // 温度
                }
            }
                
            if (DeviceInfo.UseHumiditySim)
            {
                GennerateRandomData(ref lastRandom[1], ref order[1], DeviceInfo.MinHumiditySim, DeviceInfo.MaxHumiditySim);
                DeviceInfo.Humidity = lastRandom[1];
            }
            else
            {
                //if (resp.Length < 5 || resp[0] != 0x01 || resp[1] != 0x03)
                //{
                //    ShowMessage("设备响应异常，请检查连接或设备状态！", "通信异常", "Orange");
                //    return;
                //}
                if (resp.Length > 0 && resp[0] == 0x01 && resp[1] == 0x03)
                {
                    DeviceInfo.Humidity = BitConverter.ToUInt16([resp[6], resp[5]]); // 湿度
                } 
            }

            if (DeviceInfo.UseBrightnessSim)
            {
                GennerateRandomData(ref lastRandom[2], ref order[2], DeviceInfo.MinBrightnessSim, DeviceInfo.MaxBrightnessSim);
                DeviceInfo.Brightness = lastRandom[2];
            }
            else
            {
                //if (resp.Length < 5 || resp[0] != 0x01 || resp[1] != 0x03)
                //{
                //    ShowMessage("设备响应异常，请检查连接或设备状态！", "通信异常", "Orange");
                //    return;
                //}
                if (resp.Length > 0 && resp[0] == 0x01 && resp[1] == 0x03)
                {
                    DeviceInfo.Brightness = BitConverter.ToUInt16([resp[8], resp[7]]); // 亮度
                }  
            }
            
            TemperatureValues.Add(DeviceInfo.Temperature);
            HumidityValues.Add(DeviceInfo.Humidity);
            BrightnessValues.Add(DeviceInfo.Brightness);

            XLabels.Add(DateTime.Now.ToString("ss"));

            // 保持20个数据点
            TemperatureValues.RemoveAt(0);
            HumidityValues.RemoveAt(0);
            BrightnessValues.RemoveAt(0);
            XLabels.RemoveAt(0);

            // 灯珠状态
            bytes[1] = 0x01;
            bytes[5] = 0x05;
            crc = CRC16(bytes);
            sendBytes = bytes.Concat(crc).ToArray();
            resp = SendAndReceive(bytes);
            if(resp != null && resp.Length > 0 && resp[0] == 0x01 && resp[1] == 0x01)
            {
                LightList[0].State = (resp[3] & 1) != 0; // 灯1
                LightList[1].State = (resp[3] & 2) != 0; // 灯2
                LightList[2].State = (resp[3] & 4) != 0; // 灯3
                LightList[3].State = (resp[3] & 8) != 0; // 灯4
                LightList[4].State = (resp[3] & 16) != 0; // 灯5
                // 统一控制状态
                LightList[5].State = (resp[3] & 31) == 31;
            }
        }

        private void GennerateRandomData(ref int randomValue, ref bool order, int min, int max)
        {
            if (randomValue < min)
            {
                randomValue = min;
                order = true; // 切换为递增
            }
            else if (randomValue > max)
            {
                randomValue = max;
                order = false; // 切换为递减
            }
            else
            {
                if (order)
                {
                    randomValue += random.Next(1, 20); // 增加1-2
                    if (randomValue > max)
                    {
                        randomValue = max;
                        order = false;
                    }
                }
                else
                {
                    randomValue -= random.Next(1, 20); // 减少1-2
                    if (randomValue < min)
                    {
                        randomValue = min;
                        order = true;
                    }
                }
            }
        }

        private static readonly object _lock = new object();
        private byte[] SendAndReceive(byte[] bytes)
        {
            lock (_lock)
            {
                serialPort.Write(bytes, 0, bytes.Length);

                Task.Delay(100).Wait(); // 等待设备响应

                byte[] resp = new byte[serialPort.BytesToRead]; // 清空接收缓冲区
                serialPort.Read(resp, 0, resp.Length);

                return resp;
            }
        }

        /// <summary>
        /// 计算Modbus CRC16校验码
        /// </summary>
        /// <param name="bytes">需要校验的数据</param>
        /// <returns>2字节CRC校验码，低字节在前，高字节在后</returns>
        private byte[] CRC16(byte[] bytes)
        {
            ushort crc = 0xFFFF;
            for (int i = 0; i < bytes.Length; i++)
            {
                crc ^= bytes[i];
                for (int j = 0; j < 8; j++)
                {
                    if ((crc & 0x0001) != 0)
                    {
                        crc >>= 1;
                        crc ^= 0xA001;
                    }
                    else
                    {
                        crc >>= 1;
                    }
                }
            }
            // 返回低字节在前，高字节在后
            return new byte[] { (byte)(crc & 0xFF), (byte)((crc >> 8) & 0xFF) };
        }

    }
}
